from MainWindow import Ui_MainWindow
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import PyQt5.QtCore as QtCore
import sys
import cv2

from CommandSender import CommandSender
from ImageManager import ImageManager
from BackendThread import BackendThread
from ConfigFile import *
from ParaseInfo import Paraser
from ImageProcessor import ImageProcessor, RoadImageProcessor
from EquipmentManager import Equipment


class MyWindow(QMainWindow,Ui_MainWindow):
    def __init__(self):
        super(MyWindow, self).__init__()
        self.windowInit()
        self.parameterInit()
        self.componentInit()
        self.signalConnect()

    def windowInit(self):
        '''
        窗口基本属性初始化设置
        :return: none
        '''
        # 窗口样式设置
        self.setupUi(self)
        self.resize(2200, 1300)
        # 鼠标跟踪设置
        self.setMouseTracking(True)
        self.label.setMouseTracking(True)
        self.centralwidget.setMouseTracking(True)
        # 控件样式设置
        self.tabWidget.setStyleSheet("background-color:rgb(31,31,31);color:rgb(200,200,200);")  # 设置tab的颜色
        self.tabWidget.setCurrentIndex(0)
        # self.enableCombox("all_disable")
        self.comboBox_SetTime.setCursor(QtCore.Qt.PointingHandCursor)
        self.comboBox_SetLight.setCursor(QtCore.Qt.PointingHandCursor)
        self.comboBox_SetMode.setCursor(QtCore.Qt.PointingHandCursor)
        self.btn_SendCommand.setCursor(QtCore.Qt.PointingHandCursor)


    def componentInit(self):
        '''
        使用到的组件的初始化
        :return: none
        '''
        self.imgPainter = QPainter()  # 用于动态绘制图片
        self.imageManager = ImageManager() # 图片管理器
        self.pointDistanceUpdate()
        self.backend = BackendThread(self.equipments) # 后台云端数据获取器
        self.sender = CommandSender() # 指令发送器
        self.paraser = Paraser() # 指令解析器：“将字典转换为str”

    def parameterInit(self):
        '''
        参数初始化
        :return: none
        '''
        self.singleOffset = QPoint(-30, -284)  # 初始化偏移值
        self.pointList = [[0, 0] for _ in range(len(point_list))]
        self.equipments = []
        self.isLeftPressed = bool(False)  # 图片被点住(鼠标左键)标志位
        self.text = "" # textBrowser输出的信息
        for i in range(len(point_list)):
            workStatus, ak, sk, deviceId = equipLoginList[i]
            self.equipments.append(Equipment(i, workStatus, ak, sk, deviceId))
        self.label_EquipNum.setText(str(len(point_list)))
        self.__roadWidth = [1, 2, 2, 3, 4, 5, 5, 5, 5]
        self.__roadWidthIndex = 0

    def signalConnect(self):
        '''
        连接信号与槽
        :return: none
        '''
        self.backend.checkFinishFlag.connect(self.showEquipInfo)
        self.backend.start()
        self.btn_SendCommand.clicked.connect(self.sendcontrolcommand)
        self.comboBox_SetMode.currentIndexChanged.connect(self.comboxChanged)

    def showEquipInfo(self, equipOnlineList):
        '''
        先更新地图
        再判断是否有point被点击
        如果有则显示该点的equipment的信息
        如果没有则显示默认界面
        :param equipOnlineList: 在线设备的id号列表
        :return: none
        '''
        self.label_OnlineNum.setText(str(len(equipOnlineList)))
        self.imageManager.pointOnlineUpdate(equipOnlineList)
        if self.imageManager.checkClicked():
            onlineEquipIndex = self.imageManager.getClickIndex()
            self.setEquipInfoUI(self.equipments[onlineEquipIndex])
        else:
            self.setDefaultUI()

    def setDefaultUI(self):
        '''
        没有点击任何点的情况下不会展示数据
        :return:
        '''
        self.label_EquipName.setText("无")
        self.label_EquipName_2.setText("无")
        self.label_EquipStatus.setText("无")
        self.label_EquipStatus_2.setText("无")
        self.label_ImageShow.setText("")
        self.browser_CrossInfo.setText("")
        self.label_UpdateTime.setText("无")
        self.label_CrossInfoTitle.setText("十字路口拥堵状态图：")
        self.label_ImageShowTitle.setText("十字路口状态详情：")
        self.label_ImageShow.setPixmap(QPixmap(""))
        self.enableCombox("all_disable")

    def setEquipInfoUI(self, equipment):
        '''
        展示设备的info信息，包括设备名，设备状态，十字路口信息和更新时间
        :param equipment:
        :return:
        '''
        self.label_EquipName.setText("Hisilicon-路口" + str(equipment.equipId))
        self.label_EquipName_2.setText("Hisilicon-路口" + str(equipment.equipId))
        if equipment.getOnlineStatus() == "ONLINE":
            self.label_EquipStatus.setText("在线")
            self.label_EquipStatus_2.setText("在线")
            self.label_CrossInfoTitle.setText("十字路口拥堵状态图：")
            self.label_ImageShowTitle.setText("十字路口状态详情：")
            self.enableCombox("all_enable")
        elif equipment.getOnlineStatus() == "OFFLINE":
            self.label_EquipStatus.setText("离线")
            self.label_EquipStatus_2.setText("离线")
            self.label_CrossInfoTitle.setText("十字路口拥堵状态图（历史信息）：")
            self.label_ImageShowTitle.setText("十字路口状态详情（历史信息）：")
            self.enableCombox("all_disable")
        else:
            self.label_EquipStatus.setText("未知")
            self.label_EquipStatus_2.setText("未知")
            self.label_CrossInfoTitle.setText("十字路口拥堵状态图：")
            self.label_ImageShowTitle.setText("十字路口状态详情：")
            self.enableCombox("all_disable")

        if equipment.getWorkStatus():
            self.showreportinfo(equipment.getCrossInfo())
        else:
            self.label_ImageShow.setText("无数据")
            self.browser_CrossInfo.setText("无数据")
            self.label_UpdateTime.setText("无数据")

    def enableCombox(self, status):
        '''
        下拉框使能统一
        :param status:
        :return:
        '''
        if status == "all_disable":
            self.comboBox_SetMode.setEnabled(False)
            self.comboBox_SetLight.setEnabled(False)
            self.comboBox_SetTime.setEnabled(False)
            self.btn_SendCommand.setEnabled(False)
        else:
            self.comboBox_SetMode.setEnabled(True)
            self.btn_SendCommand.setEnabled(True)
            self.comboxChanged()

    def comboxChanged(self):
        '''
        设置下拉框：当选中 自动模式 的时候，时间和状态不可选。
        :return: none
        '''
        if self.comboBox_SetMode.currentIndex() == 1:
            self.comboBox_SetLight.setEnabled(False)
            self.comboBox_SetTime.setEnabled(False)
        else:
            self.comboBox_SetLight.setEnabled(True)
            self.comboBox_SetTime.setEnabled(True)

    def showreportinfo(self, info):
        '''
        显示十字路口详细信息
        :param info: 接收到的信息
        :return: none
        '''
        if info["status"] == "normal":
            # 显示文字信息
            text = self.paraser.info2str(info)
            self.label_UpdateTime.setText(str(info["current_time"]))
            self.browser_CrossInfo.setText(text)
            if info["current_mode"] == "AutoMode":
                self.label_EquipCurrentMode.setText("自动模式")
            else:
                self.label_EquipCurrentMode.setText("控制模式")
        elif info["status"] == "internet_error":
            self.browser_CrossInfo.setText("发生未知错误")
            self.label_UpdateTime.setText("发生未知错误")
            self.label_EquipCurrentMode.setText("无数据")

    def sendcontrolcommand(self):
        '''
        下发指令按钮的槽函数
        :return: none
        '''
        if self.comboBox_SetMode.currentIndex() == 1: # 发送自动模式代码
            if self.sender.sendautomodecommand():
                self.informationWidget("提示", "指令发送成功！", 1.5)
            else:
                QMessageBox.warning(self, "警告", "指令发送失败！", QMessageBox.Ok, QMessageBox.Ok)
        else:   # 发送控制模式代码
            directionList = ["TimerSNSG","TimerTNSG","TimerSEWG","TimerTEWG"]
            timeList = [10, 20, 30, 40, 50, 65534]
            directionIdx = self.comboBox_SetLight.currentIndex()
            timeIdx = self.comboBox_SetTime.currentIndex()
            if self.sender.sendcontrolcommand(directionList[directionIdx], timeList[timeIdx]):
                self.informationWidget("提示", "指令发送成功！", 1.5)
            else:
                QMessageBox.warning(self, "警告", "指令发送失败！", QMessageBox.Ok, QMessageBox.Ok)

    def informationWidget(self, title, message, delay):
        '''
        消息弹窗
        :param title: 弹窗标题
        :param message: 弹窗信息
        :param delay: 弹窗显示时长
        :return: none
        '''
        msgBox = QMessageBox()
        msgBox.setWindowTitle(title)
        msgBox.setText(message)
        msgBox.setStandardButtons(QMessageBox.Ok)
        msgBox.setDefaultButton(QMessageBox.Ok)
        msgBox.button(QMessageBox.Ok).animateClick(1000 * delay)
        msgBox.exec()

    def paintEvent(self, event):
        '''
        重写背景图片绘制函数
        :param event: no use
        :return: none
        '''
        self.imgPainter.begin(self)  # 无begin和end,则将一直循环更新
        self.paintFunc()
        self.labelPaint()
        self.imgPainter.end()  # 无begin和end,则将一直循环更新

    def labelPaint(self):
        '''
        绘制label中的略缩图
        :param pixmap:
        :return:
        '''
        if self.imageManager.checkClicked(): # 如果有point被点击则绘制被点击的设备的信息
            clickEquip = self.equipments[self.imageManager.getClickIndex()]
            if clickEquip.getInfoFlag():
                mapWidth = min(self.label_ImageShow.width(), self.label_ImageShow.height())
                pix = QPixmap()
                pix.load("sources/detail/img_background.png")
                newPix = pix.scaled(mapWidth, mapWidth)
                self.label_ImageShow.setPixmap(newPix)
                imageProcessor = ImageProcessor(self.label_ImageShow.pixmap())
                imageProcessor.paintImg(clickEquip.getCongestionInfo()[1])

    def paintFunc(self):
        '''
        绘背景图，point点图标，以及道路拥堵图
        :return: none
        '''
        # 绘制地图背景
        self.imgPainter.drawPixmap(self.singleOffset, self.imageManager.getBackground())
        # 绘制道路拥堵图
        roadProcessor = RoadImageProcessor(self.imgPainter, self.singleOffset, self.imageManager.getBackgroundSize())
        if self.equipments[3].getInfoFlag():
            roadProcessor.paintRoad(self.equipments[3].getCongestionInfo()[1], self.__roadWidth[self.__roadWidthIndex])
        # 绘制point点图
        self.pointAxisUpdate()
        for i in range(len(self.pointList)):
            pointIcon = self.imageManager.getPointIcon(i)
            locationOffset = QPoint(int(self.pointList[i][0] - pointIcon.width() / 2),
                                    int(self.pointList[i][1] - pointIcon.height()/2))
            self.imgPainter.drawPixmap(locationOffset, pointIcon)

    def mousePressEvent(self, event):
        '''
        重写鼠标点响应函数
        :param event: 鼠标点击事件
        :return: none
        '''
        if event.buttons() == QtCore.Qt.LeftButton:  # 左键按下
            print("鼠标左键单击")  # 响应测试语句
            self.preMousePosition = event.pos()  # 获取鼠标当前位置
            self.isLeftPressed = True  # 左键按下(图片被点住),置Ture

    def mouseReleaseEvent(self, event):
        '''
        重写鼠标松开事件响应
        :param event: 鼠标事件
        :return: none
        '''
        if event.button() == QtCore.Qt.LeftButton:  # 左键释放
            self.isLeftPressed = False  # 左键释放(图片被点住),置False
            self.setCursor(QtCore.Qt.ArrowCursor)
            if self.pointStatusUpdate(event, "click"):
                self.tabWidget.setCurrentIndex(1)
            print("鼠标左键松开")  # 响应测试语句
        elif event.button() == Qt.RightButton:  # 右键释放
            # self.showPosition(event)
            print("鼠标右键松开")  # 响应测试语句

    def showPosition(self, event):
        '''
        将当前的鼠标位置显示到browser中  debug用
        :param event: 鼠标事件
        :return: none
        '''
        x1 = event.x()
        y1 = event.y()
        x0 = self.singleOffset.x()
        y0 = self.singleOffset.y()
        pos_x = x1 - x0
        pos_y = y1 - y0
        w = self.imageManager.getBackgroundSize().width()
        h = self.imageManager.getBackgroundSize().height()
        self.text = self.text + "point: ({},{})/({},{})\n".format(pos_x, pos_y, w, h)
        self.textBrowser.setText(self.text)

    def mouseMoveEvent(self, event):
        '''
        重写鼠标移动响应事件
        :param event: 鼠标事件
        :return: none
        '''
        # self.label_2.setText("x:{}, y:{}".format(event.x(), event.y()))
        self.pointStatusUpdate(event, "touch")
        self.repaint()
        if self.isLeftPressed:  # 左键按下
            self.setCursor(QtCore.Qt.ClosedHandCursor)
            print("鼠标左键按下，移动鼠标")  # 响应测试语句
            self.endMousePosition = event.pos() - self.preMousePosition  # 鼠标当前位置-先前位置=单次偏移量
            self.singleOffset = self.singleOffset + self.endMousePosition  # 更新偏移量
            self.offsetcheck()
            self.preMousePosition = event.pos()  # 更新当前鼠标在窗口上的位置，下次移动用
            self.pointDistanceUpdate()
            self.repaint()  # 重绘
            pass
        else: # 左键没有按下，鼠标只是touch一下
            if self.imageManager.touchFlagNum() == 1:
                self.setCursor(QtCore.Qt.PointingHandCursor)
                self.label.setToolTip("第 {} 个路口".format(self.imageManager.touchFlagIndex()))
                self.label.setToolTipDuration(2000)
            else:
                self.setCursor(QtCore.Qt.ArrowCursor)
                self.label.setToolTip("")

    def wheelEvent(self, event):
        '''
        重写鼠标滑轮滚动的响应函数
        :param event: 鼠标事件
        :return: none
        '''
        angle = event.angleDelta() / 8  # 返回QPoint对象，为滚轮转过的数值，单位为1/8度
        angleY = angle.y()  # 竖直滚过的距离
        if angleY > 0:  # 滚轮上滚 放大画面
            if self.imageManager.backgroundScale(6, 5):
                print("鼠标中键上滚")
                newX = event.x() - int((event.x() - self.singleOffset.x()) * 6 / 5)
                newY = event.y() - int((event.y() - self.singleOffset.y()) * 6 / 5)
                self.singleOffset = QPoint(newX, newY)  # 更新偏移量
                self.imageManager.rescaleRange(1)
                self.pointDistanceUpdate()
                self.__roadWidthIndex += 1
                self.repaint()  # 重绘
        else:  # 滚轮下滚 缩小画面
            if self.imageManager.backgroundScale(5, 6):
                print("鼠标中键下滚")
                newX = event.x() - int((event.x() - self.singleOffset.x()) * 5 / 6)
                newY = event.y() - int((event.y() - self.singleOffset.y()) * 5 / 6)
                self.singleOffset = QPoint(newX, newY)  # 更新偏移量
                self.offsetcheck()
                self.imageManager.rescaleRange(-1)
                self.pointDistanceUpdate()
                self.__roadWidthIndex -= 1
                self.repaint()  # 重绘

    def offsetcheck(self):
        '''
        检查singleOffset的值，保证图片不划出视线外
        :return: none
        '''
        if self.singleOffset.x() > 0:
            self.singleOffset.setX(0)
        if self.singleOffset.y() > 0:
            self.singleOffset.setY(0)
        if self.singleOffset.x() + self.imageManager.getBackgroundSize().width() < self.size().width():
            self.singleOffset.setX(self.size().width() - self.imageManager.getBackgroundSize().width())
        if self.singleOffset.y() + self.imageManager.getBackgroundSize().height() < self.size().height():
            self.singleOffset.setY(self.size().height() - self.imageManager.getBackgroundSize().height())

    def pointAxisUpdate(self):
        '''
        根据singleOffset的值更新每个point的坐标
        :return:
        '''
        for i in range(len(point_list)):
            factor = self.imageManager.getBackgroundSize().width()/reference_size
            self.pointList[i][0] = self.singleOffset.x()+int(point_list[i][0]*factor)
            self.pointList[i][1] = self.singleOffset.y()+int(point_list[i][1]*factor)

    def pointStatusUpdate(self, event, flag):
        '''
        检查鼠标是否指向某一point
        :param event: 鼠标事件
        :return: none
        '''
        x = event.x()
        y = event.y()
        if flag == "touch":
            for i in range(len(self.pointList)):
                effectiveWidth = self.imageManager.getPointIcon(i).width() / 3 * 2
                if x > self.pointList[i][0] - effectiveWidth / 2 and x < self.pointList[i][0] + effectiveWidth / 2 and y > self.pointList[i][1] - effectiveWidth and y < self.pointList[i][1]:
                    self.imageManager.setTouchFlag(i, True)
                else:
                    self.imageManager.setTouchFlag(i, False)
            self.imageManager.pointStatusUpdate()
            return True
        else:
            choose_index = 65535
            for i in range(len(self.pointList)):
                effectiveWidth = self.imageManager.getPointIcon(i).width() / 3 * 2
                if x > self.pointList[i][0] - effectiveWidth / 2 and x < self.pointList[i][0] + effectiveWidth / 2 and y > self.pointList[i][1] - effectiveWidth and y < self.pointList[i][1]:
                    self.imageManager.clickFlagFlip(i)
                    choose_index = i
            for j in range(len(self.pointList)):
                if choose_index != 65535:
                    if j != choose_index:
                        self.imageManager.setClickFlag(j, False)
            self.imageManager.pointStatusUpdate()
            if choose_index == 65535:
                return False
            else:
                return True

    def pointDistanceUpdate(self):
        '''
        根据singleOffset更改视觉中心点，重新计算所有点的距离
        视觉中心点坐标（相对于屏幕左上角）：(1500,750)
        :return: none
        '''
        # 将视觉中心映射到图像上
        viewCenter = (1500-self.singleOffset.x(), 750-self.singleOffset.y())
        self.imageManager.pointDistanceUpdate(viewCenter)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MyWindow()
    window.showMaximized()
    sys.exit(app.exec_())